import 'package:equatable/equatable.dart';
import 'package:im_app/im/dao/ImGroupDao.dart';
import 'package:im_app/im/util/UiUtil.dart';

import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../util/LoggerUtil.dart';
import 'BaseBloc.dart';

final class SelectGroupUsersCubit extends BaseBloc<SelectGroupUsersEvent, SelectGroupUsersState> {

  final _logger = createLogger();

  final String groupCode;
  final bool isAudio;

  SelectGroupUsersCubit(this.groupCode, this.isAudio, Set<String>? existedUserIdSet) :
    super(SelectGroupUsersState.loading (existedUserIdSet?? new Set<String>())) {

    on<SelectGroupUsersAddUserEvent>((event, emit) {
      _addUser(state, event.user);
    });
    on<SelectGroupUsersRemoveUserEvent>((event, emit){
      _removeUser(state, event.user);
    });
    on<SelectGroupUsersSearchEvent>((event, emit){
      _search(state, event.search);
    });
    on<SelectGroupUsersResetEvent>((event, emit){
      _reset(state);
    });
    on<SelectGroupUsersCancelEvent>((event, emit){
      _cancel(state);
    });
  }

  _addUser(SelectGroupUsersState state, ImUser user) {
    Map<String, ImUser> selectUserMap = copyMap(state.selectedUserMap);
    List<ImUser> selectedUsers = copyList(state.selectedUsers);
    selectUserMap[user.userId] = user;
    selectedUsers.add(user);

    SelectGroupUsersState newState = state.copy(selectedUsers: selectedUsers, selectedUserMap: selectUserMap);
    emit(newState);
  }

  _removeUser(SelectGroupUsersState state, ImUser user) {
    Map<String, ImUser> selectUserMap = copyMap(state.selectedUserMap);
    selectUserMap.remove(user.userId);

    List<ImUser> selectedUsers = copyList(state.selectedUsers);
    selectedUsers.remove(user);
    SelectGroupUsersState newState = state.copy(selectedUsers: selectedUsers, selectedUserMap: selectUserMap);
    emit(newState);
  }

  _search(SelectGroupUsersState state, String search) {
    List<ImUser> showUsers = state.allUsers.where((u)=>u.userName!.contains(search) || u.userId!.contains(search))
        .toList();
    var newState = state.copy(showUsers: showUsers, search: search);
    emit(newState);
  }

  _reset(SelectGroupUsersState state) async {
    var newState = SelectGroupUsersState.success(state.existedUserIdSet, state.allUsers, state.letters, state.letterSizeMap);
    emit(newState);
  }

  _cancel(SelectGroupUsersState state) {
    SelectGroupUsersState newState = state.copy(selectedUsers: <ImUser>[], selectedUserMap: <String, ImUser>{});
    emit(newState);
  }

  Future<void> loadData(Set<String> existedUserSet) async {
    _logger.i('SelectGroupUsersCubit loadData!!!!!!!!!!', time: DateTime.now());
    var groupDao = ImGroupDao();
    String loginUserId = UiUtil.getLoginUser().userId;
    ImGroup? group = await groupDao.getByCodeAndUserId(groupCode, loginUserId);
    await groupDao.loadGroupUsers(group!);
    List<ImUser> allUsers = group!.groupUserList!.map((gu)=>gu.user!).toList();
    allUsers.sort((u1, u2)=>(u1.firstLetter??'').compareTo((u2.firstLetter??'')));
    List<String> letters = _calcLetter(allUsers);
    SelectGroupUsersState newState = SelectGroupUsersState.success(existedUserSet, allUsers, letters, _calcLetters(allUsers));
    emit(newState);
  }

  List<String> _calcLetter(List<ImUser> users) {
    Set<String> letterSet = users.map((u)=>(u.firstLetter??'#').toUpperCase()).toSet();
    List<String> letters = letterSet.toList();
    letters.sort();
    return letters;
  }

  Map<String, int> _calcLetters(List<ImUser> users) {
    Map<String, int> map = {};
    for (var user in users) {
      var key = (user.firstLetter??'#').toUpperCase();
      if (map.containsKey(key)) {
        int value = map[key]!;
        map[key] = value + 1;
      } else {
        map[key] = 1;
      }
    }
    return map;
  }
}

final class SelectGroupUsersState extends Equatable {
  final Set<String> existedUserIdSet;
  final LoadingState state;
  final List<ImUser> selectedUsers;
  final Map<String, ImUser> selectedUserMap;
  final List<ImUser> allUsers;
  final List<ImUser> filterUsers;
  final List<String> letters;
  final Map<String, int> letterSizeMap;
  final String search;

  const SelectGroupUsersState._({
    required this.existedUserIdSet,
    this.state = LoadingState.loading,
    this.allUsers = const <ImUser>[],
    this.filterUsers = const <ImUser>[],
    this.selectedUsers = const <ImUser>[],
    this.selectedUserMap = const <String, ImUser>{},
    this.letters = const <String>[],
    this.letterSizeMap = const {},
    this.search = '',
  });

  SelectGroupUsersState copy({Set<String>? existedUserIdSet, List<ImUser>? allUsers, List<ImUser>? selectedUsers,
    Map<String, ImUser>? selectedUserMap, List<ImUser>? showUsers, List<String>? letters, Map<String, int>? letterSizeMap,
    String? search, String? forwardRouter, ImSession? forwardSession}) {
    return SelectGroupUsersState._(
      existedUserIdSet: existedUserIdSet ?? this.existedUserIdSet,
      allUsers: allUsers ?? this.allUsers,
      selectedUsers: selectedUsers ?? this.selectedUsers,
      selectedUserMap: selectedUserMap ?? this.selectedUserMap,
      filterUsers: showUsers ?? this.filterUsers,
      letters: letters ?? this.letters,
      letterSizeMap: letterSizeMap ?? this.letterSizeMap,
      search: search ?? this.search,
      state: this.state,
    );
  }

  const SelectGroupUsersState.loading(Set<String> existedUserIdSet) : this._(existedUserIdSet: existedUserIdSet);

  const SelectGroupUsersState.success(Set<String> existedUserIdSet, List<ImUser> allUsers, List<String> letters,
    Map<String, int> letterSizeMap) : this._(state: LoadingState.success, existedUserIdSet: existedUserIdSet,
      allUsers: allUsers, filterUsers: allUsers, letters: letters, letterSizeMap: letterSizeMap);

  @override
  List<Object?> get props => [state, filterUsers, selectedUsers, letters, search];
}


abstract class SelectGroupUsersEvent {}
final class SelectGroupUsersAddUserEvent extends SelectGroupUsersEvent {
  final ImUser user;
  SelectGroupUsersAddUserEvent(this.user);
}
final class SelectGroupUsersRemoveUserEvent extends SelectGroupUsersEvent {
  final ImUser user;
  SelectGroupUsersRemoveUserEvent(this.user);
}
final class SelectGroupUsersSearchEvent extends SelectGroupUsersEvent {
  final String search;
  SelectGroupUsersSearchEvent(this.search);
}
final class SelectGroupUsersResetEvent extends SelectGroupUsersEvent {
  SelectGroupUsersResetEvent();
}
final class SelectGroupUsersCancelEvent extends SelectGroupUsersEvent {
  SelectGroupUsersCancelEvent();
}